package com.mingqijia.gassafety.authority.security.filter;

import com.gap.basic.base.CommonResponse;
import com.mingqijia.gassafety.authority.security.user.SecurityUserLoginHolder;
import com.mingqijia.gassafety.authority.security.valueobject.ManagerVO;
import com.mingqijia.gassafety.shared.constant.Constants;
import com.mingqijia.gassafety.shared.handler.GlobalAuthenticationException;
import com.mingqijia.gassafety.shared.jwt.JwtAware;
import com.mingqijia.gassafety.shared.jwt.JwtProvider;
import com.mingqijia.gassafety.shared.utils.ApplicationUtils;
import com.mingqijia.gassafety.shared.utils.MappingTools;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;


/**
 * token校验,引用的stackoverflow一个答案里的处理方式
 * @author Damon S.
 * @version v1.0.1
 * @date 2020年07月25日 12:00
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Value("${jwt.header}")
    private String tokenHeader;

    private final SecurityUserLoginHolder holder;
    private final JwtProvider tProvider;
    private final String token4Irs = "0cc8d63040ec44a19bf57d88acf2b831";
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {

        // 单独处理irs数据提取请求
        String irsToken = obtainCaptcha(request);
        if (Objects.equals(irsToken, token4Irs)
                && (request.getRequestURI().contains("/hangzhou/v1/irs"))) {
            ManagerVO backend = new ManagerVO();
            backend.setUsername("irs");
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                    backend, Constants.STR_EMPTY, backend.getAuthorities());
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authentication);

            filterChain.doFilter(request, response);
            return;
        }
        // =================================
        String tokenValue = request.getHeader(tokenHeader);
        if (ObjectUtils.isEmpty(tokenValue) || !tokenValue.startsWith(Constants.PREFIX_BEARER)
                || request.getRequestURI().contains(Constants.TOKEN_URL)) {
            filterChain.doFilter(request, response);
            return;
        }

        JwtAware jwtToken;
        try {
            jwtToken = tProvider.parseToken(tokenValue);
            if (tProvider.tokenExpired(jwtToken) || Objects.nonNull(
                    SecurityContextHolder.getContext().getAuthentication())) {
                throw new GlobalAuthenticationException("Token已失效");
            }
        } catch (ExpiredJwtException | GlobalAuthenticationException e) {
            ApplicationUtils.writeOutJson(response, CommonResponse.failure(10000, "Token已失效"));
            return;
        }

        ManagerVO backend = holder.findManagerByUsername(jwtToken.getUniqueName());
        if (Objects.nonNull(backend.getLogoutAt()) && jwtToken.getExpiredAt().after(backend.getLogoutAt())
                && MappingTools.DEFAULT_MIN_LDT.before(backend.getLogoutAt())) {
            ApplicationUtils.writeOutJson(response, CommonResponse.failure(10000, "Token已失效"));
            return;
        }
        if (!backend.isEnabled()) {
            ApplicationUtils.writeOutJson(response, CommonResponse.failure(10000, "账户已禁用"));
            return;
        }

        // 将用户对象设置为principle
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                backend, Constants.STR_EMPTY, backend.getAuthorities());
        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        SecurityContextHolder.getContext().setAuthentication(authentication);

        filterChain.doFilter(request, response);
    }

    private String obtainCaptcha(HttpServletRequest request) {
        return String.valueOf(request.getHeader("token"));
    }
}
